package com.bestv.search.management.datasyn;

import com.bestv.search.common.dataSource.DataSourceKey;
import com.bestv.search.common.dataSource.DataSourceKeyUtil;
import com.bestv.search.common.model.Channel;
import com.bestv.search.common.model.Schedule;
import com.bestv.search.common.model.Type;
import com.bestv.search.common.model.uid.UID;
import com.bestv.search.common.util.CharUtil;
import com.bestv.search.common.util.ChineseCharToEn;
import com.bestv.search.common.util.StringConst;
import org.apache.commons.configuration.PropertiesConfiguration;
import org.apache.commons.configuration.reloading.FileChangedReloadingStrategy;

import java.io.UnsupportedEncodingException;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.Statement;
import java.text.SimpleDateFormat;
import java.util.Arrays;
import java.util.Date;
import java.util.List;
import java.util.Map;

/**
 * @author Michael Wang
 */

// $Id$
public class VisDbScheduleSyncer extends ProgramSyncerImpl {

    final static String sDBDriver = "oracle.jdbc.driver.OracleDriver";
    final static String filterFile = "filterWords.properties";

    String orclUrl = null;
    String encoding = "ISO8859_1";
    String user = null;
    String pass = null;
    String scheduleView = null;

    public VisDbScheduleSyncer(Map<String, String> p) throws Exception {
        this.setProps(p);
        justDoIt();
    }

    @Override
    public boolean init(Map<String, String> properties) {
        if (!initLastSyncTime(StringConst.BESTV_VIS, 1, StringConst.VIS_Schedule_SYNC_TIME)) {
            return false;
        }
        if (props.get("orclUrl") == null || props.get("orclUrl").length() == 0) {
            logger.error("orclUrl is empty!");
            result = false;
            return false;
        }
        if (props.get("schedule") == null || props.get("schedule").length() == 0) {
            logger.error("schedule view is empty!");
            result = false;
            return false;
        }
        if (props.get("encoding") == null || props.get("encoding").length() == 0) {
            logger.warn("encoding is empty, use ISO8859_1");
        } else {
            encoding = props.get("encoding");
        }
        orclUrl = props.get("orclUrl");
        user = props.get("user");
        pass = props.get("pass");
        scheduleView = props.get("schedule");
        return true;
    }

    @Override
    public boolean updateProgram() throws Exception {
        logger.info("Update the expired schedules...");
        DataSourceKey dsKey = DataSourceKeyUtil.convert(systemCache.getLocalDataSourceKey());
        List<Schedule> expiredSchedules = schm.getExpiredSchedules(dsKey);
        for (Schedule expiredSchedule : expiredSchedules) {
            expiredSchedule.setUpdateFlag(2);
            expiredSchedule.setUpdateTimeForIndex(new Date());
            vm.saveUpdateInfo(dsKey, expiredSchedule);
        }

        logger.info("Now read from vis db schedules and update to search's");
        thisSyncTime = lastSyncSuccessfullTime;

        // Gets filters words that don't want to searched
        String[] filtersWords = getFilterWords();
        // Gets filters Channel
        List<String> filtersChannel = getFilterChannels();

        Connection conn = null;
        ResultSet rs = null;
        Statement stmt = null;

        String syncMessage = "Success sync schedule from Vis system @ " + new Date();
        try {
            Class.forName(sDBDriver);
            conn = DriverManager.getConnection(orclUrl, user, pass);
            stmt = conn.createStatement();

            rs = stmt.executeQuery("select * from " + scheduleView + " where last_update_time >= " + "to_date('"
                    + timeformat.format(lastSyncSuccessfullTime) + "','YYYY-MM-DD HH24:MI:SS') order by valid_time");
            logger.info("A new batch begins at schedule_update_time " + timeformat.format(lastSyncSuccessfullTime));

            boolean isNew;
            while (rs.next()) {
                Schedule schedule = new Schedule();
                schedule.setHitCount(0);
                Date now = new Date();
                schedule.setUpdateFlag(0);
                Date ut = rs.getTimestamp("last_update_time");
                if (thisSyncTime == null || ut.after(thisSyncTime)) {
                    thisSyncTime = ut;
                }
                try {
                    List<Schedule> sl = schm.getSchedulesByCode(dsKey, rs.getString("code"));
                    if (sl != null && sl.size() > 0) {
                        isNew = false;
                        schedule = sl.get(0);
                        schedule.setUpdateFlag(1);
                    } else {
                        isNew = true;
                    }
                    schedule.setStatus(1);
                    schedule.setUpdateTime(now);
                    schedule.setUpdateTimeMillis(now.getTime());
                    schedule.setUpdateTimeForIndex(now);
                    schedule.setType(new Type(5L, "schedule", "节目单"));
                    schedule.setCode(rs.getString("code"));
                    String name = unifyStr(rs.getString("name"));

                    // Check name whether contains word that need to be
                    // filtered
                    if (containsSubWordInArray(filtersWords, name)) {
                        // Contains, set updateFlag =2
                        schedule.setUpdateFlag(2);
                        logger.info("Name contains word that need to be filtered, offline it by mediaCode "
                                + schedule.getCode());
                    }

                    schedule.setName(name);
                    if (schedule.getNamePY() == null || "".equals(schedule.getNamePY())) {
                        String abbreviation = ChineseCharToEn.getAllFirstLetter(name);
                        String splitTokens = splitToken(name);
                        schedule.setNamePY(abbreviation + " " + CharUtil.charToNum(abbreviation) + " " + splitTokens);
                    }
                    String channelCode = rs.getString("channel_code");
                    // Channel code equals filter channel that line in
                    // filtersChannel list, off line this schedule
                    if (channelCode != null && filtersChannel.contains(channelCode)) {
                        logger.info("Channel code equals filter channel that lie in filtersChannel list, offline it by mediaCode "
                                + schedule.getCode());
                        schedule.setUpdateFlag(2);
                    }

                    schedule.setChannel(channelCode);
                    schedule.setStartPlayTime(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").parse(rs
                            .getString("start_time")));
                    schedule.setEndPlayTime(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").parse(rs.getString("end_time")));
                    schedule.setValidTime(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").parse(rs.getString("valid_time")));

                    String expireTime = rs.getString("expire_time");
                    if (expireTime != null) {
                        schedule.setExpireTime(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").parse(expireTime));
                    }
                    schedule.setP_type("节目单");
                    schedule.setBizType(bm.getBizTypeByName(dsKey, "节目单"));
                    schedule.setDomain(rs.getString("domain"));
                    Channel channel = cm.getChannelByCode(dsKey, channelCode);
                    if (channel != null) {
                        String channelName = channel.getName();
                        if (channelName.indexOf("HD") != -1 || channelName.indexOf("高清") != -1) {
                            schedule.setHd(1);
                        } else {
                            schedule.setHd(0);
                        }
                    } else {
                        schedule.setHd(0);
                    }
                    if (schedule.getName().indexOf("HD") != -1 || schedule.getName().indexOf("高清") != -1) {
                        schedule.setHd(1);
                    }

                    if (isNew) {
                        schedule.setId(new Long(UID.getUID(schedule)));
                    }
                } catch (Exception e) {
                    logger.error("read schedules error! pcode=" + rs.getString("code"));
                    e.printStackTrace();
                }
                vm.saveUpdateInfo(dsKey, schedule);
            }
        } catch (Exception e) {
            System.out.println(e);
            syncMessage = "Failed sync schedule from Vis system @ " + new Date();
            result = false;
            throw e;
        } finally {
            if (rs != null)
                rs.close();
            if (stmt != null)
                stmt.close();
            if (conn != null)
                conn.close();

            // Update Sync status.
            updateSyncStatus(StringConst.BESTV_VIS, 1, StringConst.VIS_Schedule_SYNC_TIME, syncMessage, thisSyncTime);
        }
        return true;
    }

    public void setProps(Map<String, String> props) {
        this.props = props;
    }

    String unifyStr(String s) throws UnsupportedEncodingException {
        if (s == null)
            return null;
        String toCode = encoding.equalsIgnoreCase("iso-8859-1") ? "gbk" : "utf-8";
        return new String(s.getBytes(encoding), toCode).trim();
    }

    private String[] getFilterWords() {
        PropertiesConfiguration config;
        try {
            config = new PropertiesConfiguration(filterFile);
            config.setReloadingStrategy(new FileChangedReloadingStrategy());
            String filterStr = config.getString("filter");
            return filterStr.split("_");
        } catch (Exception e) {
            logger.error("Gets filter word failed " + e.getMessage());
        }

        return null;
    }

    private boolean containsSubWordInArray(String[] array, String word) {
        if (array == null || array.length == 0 || word == null) {
            return false;
        } else {
            for (String wordInArray : array) {
                if (word.contains(wordInArray)) {
                    return true;
                }
            }
        }
        return false;
    }

    private List<String> getFilterChannels() {
        PropertiesConfiguration config;
        try {
            config = new PropertiesConfiguration(filterFile);
            config.setReloadingStrategy(new FileChangedReloadingStrategy());
            String filterStr = config.getString("channelFilter");
            return Arrays.asList(filterStr.split("_"));
        } catch (Exception e) {
            logger.error("Gets filter chnnels failed " + e.getMessage());
        }

        return null;
    }
}
